% def get_node_kind(mnemonic)
%   return "#{mnemonic.gsub('.', '_').upcase}"
% end
%
% def get_format_name(mnemonic)
%   return "#{mnemonic.gsub('.', '_').upcase}" + "_FORMATS"
% end
/**
 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Autogenerated file -- DO NOT EDIT!

#ifndef ES2PANDA_COMPILER_GEN_IR_ISA_H
#define ES2PANDA_COMPILER_GEN_IR_ISA_H

#include <ir/irnode.h>
#include <gen/formats.h>
#include <assembly-ins.h>

namespace panda::es2panda::compiler {

class Label : public IRNode {
public:
    explicit Label(const ir::AstNode* node, std::string id) : IRNode(node), id_(std::move(id)) {}

    static constexpr std::string_view PREFIX = "LABEL_";

    Formats GetFormats() const override
    {
        return Span<const Format>(nullptr, nullptr);
    }

    const std::string &Id() const
    {
        return id_;
    }

    size_t Registers([[maybe_unused]] std::array<VReg*, MAX_REG_OPERAND>* regs) override
    {
        return 0;
    }

    size_t Registers([[maybe_unused]] std::array<const VReg*, MAX_REG_OPERAND>* regs) const override
    {
        return 0;
    }

    void Transform(pandasm::Ins *ins) const override
    {
        ins->opcode = pandasm::Opcode::INVALID;
        ins->set_label = true;
        ins->label = id_;
    }

    ICSlot SetIcSlot(IcSizeType currentSlot) override
    {
        return 0;
    }

    bool InlineCacheEnabled() override
    {
        return false;
    }

    ICSlot GetIcSlot() override
    {
        return 0;
    }

    bool oneByteSlotOnly() override
    {
        return false;
    }

    uint8_t IcSlots() override
    {
        return 0;
    }

private:
    std::string id_;
};

% def insn2node(insn)
%   mnemonic = insn.mnemonic.split('.')
%   return mnemonic.map{|el| el == '64' ? 'Wide' : el.capitalize}.join()
% end
%
% def is_Range(insn)
%   if insn.mnemonic == "callrange" or insn.mnemonic == "wide.callrange" or
%       insn.mnemonic == "callthisrange" or insn.mnemonic == "wide.callthisrange" or
%       insn.mnemonic == "newobjrange" or insn.mnemonic == "wide.newobjrange" or
%       insn.mnemonic == "createobjectwithexcludedkeys" or insn.mnemonic == "wide.createobjectwithexcludedkeys" or
%       insn.mnemonic == "supercallthisrange" or insn.mnemonic == "wide.supercallthisrange" or
%       insn.mnemonic == "supercallarrowrange" or insn.mnemonic == "wide.supercallarrowrange"
%      return true
%   end
%   return false
% end
%
% def is_VReg(name)
%     if name ==  :v
%        return true
%     end
% end
%
% def is_Acc(name)
%    if name ==  :acc
%        return true
%     end
% end
%
% def is_Imm(name)
%    if name ==  :imm
%        return true
%     end
% end
%
% def is_Id(name)
%     if %i[method_id type_id field_id string_id stringId callsite_id literalarray_id].include?(name)
%        return true
%     end
% end
%
% def get_operand_type(name, name_tmp, insn, map)
%   if is_VReg (name_tmp)
%     map['reg'].push("#{name}_")
%     return 'VReg'
%   elsif is_Imm(name_tmp)
%     if insn.properties.include? 'jump'
%       map['lbl'].push("#{name}_")
%       return "Label*"
%     end
%     map['imm'].push("#{name}_")
%     if insn.sig.include? 'imm:f64'
%       return 'double'
%     end
%       return 'int64_t'
%   elsif is_Id(name_tmp)
%     map['str'].push("#{name}_")
%     return 'util::StringView'
%   else
%     return nil
%   end
% end
%
% def get_operands(sig)
%     return [] unless sig.include? ' '
%     _, operands = sig.match(/(\S+) (.+)/).captures
%     operands = operands.split(', ')
%     end
%
% def get_ctor_args(insn)
%     operands = get_operands(insn.sig)
%     ops = Array.new
%     ctor_args = Array.new
%     op_map = Hash.new { |h, k| h[k] = [] }
%     id_count = 0
%     operands.map do |operand|
%     operand_parts = operand.split(':')
%       case operand_parts.size
%       when 1
%         name = operand_parts[0]
%       when 2
%         name, _ = operand_parts
%       when 3
%         name, _, _ = operand_parts
%       else
%         raise 'Unexpected operand string'
%       end
%
%       name_tmp = name_tmp = name.to_s.gsub(/[0-9]/, '').to_sym;
%
%       if is_Id(name_tmp)
%           name = "stringId_"
%           name.concat(id_count.to_s)
%           id_count = id_count + 1
%       end
%
%       ops.push(name)
%       type = get_operand_type(name, name_tmp, insn, op_map)
%       ctor_args.push("#{type} #{name}")
%     end
%     return ops,ctor_args,op_map
% end
%
% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
% insn = group.first
% node_kind = get_node_kind(mnemonic)
% class_name = insn2node(insn)
% is_range_op = is_Range(insn)
% base_class = "IRNode"
% ops_list,ctor_arg_list,op_map = get_ctor_args(insn)
% ctor_args = "const ir::AstNode* node" + (ctor_arg_list.length == 0 ? "" : ", ") + ctor_arg_list.map {|arg| "#{arg}"}.join(", ")
% members = ctor_arg_list.map {|arg| "#{arg}_;"}.join("\n    ")
% registers = op_map['reg'].map {|reg| "&#{reg}"}.join(", ")
% ops = (ops_list.length == 0 ? "" : ", ") + ops_list.map { |op| "#{op}_(#{op})"}.join(", ")
class <%= class_name %> : public <%= base_class %>
{
public:
    explicit <%= class_name %>(<%= ctor_args %>) : <%= base_class %>(node)<%= ops %> {}

    Formats GetFormats() const override {
        return Span<const Format>(<%= get_format_name(insn.mnemonic) %>);
    }

    size_t Registers([[maybe_unused]] std::array<VReg*, MAX_REG_OPERAND>* regs) override
    {
% reg_cnt = 0
% for reg in op_map['reg']
        (*regs)[<%= reg_cnt %>] = &<%= reg %>;
%   reg_cnt+=1;
% end
        return <%= reg_cnt %>;
    }

    size_t Registers([[maybe_unused]] std::array<const VReg*, MAX_REG_OPERAND>* regs) const override
    {
% reg_cnt = 0
% for reg in op_map['reg']
        (*regs)[<%= reg_cnt %>] = &<%= reg %>;
%   reg_cnt+=1;
% end
        return <%= reg_cnt %>;
    }

    void Transform(pandasm::Ins* ins) const override
    {
        ins->opcode = pandasm::Opcode::<%= node_kind %>;
% if op_map['reg'].length != 0
        ins->regs.reserve(<%= op_map['reg'].length %>);
% end
% if op_map['imm'].length != 0
        ins->imms.reserve(<%= op_map['imm'].length %>);
% end
% if op_map['str'].length + op_map['lbl'].length != 0
        ins->ids.reserve(<%= op_map['str'].length + op_map['lbl'].length %>);
% end
% for reg in op_map['reg']
        ins->regs.emplace_back(<%= reg %>);
% end
% for imm in op_map['imm']
        ins->imms.emplace_back(<%= imm %>);
% end
% for str in op_map['str']
        ins->ids.emplace_back(<%= str %>.Mutf8());
% end
% for lbl in op_map['lbl']
        ins->ids.emplace_back(<%= lbl %>->Id());
% end
    }

    ICSlot SetIcSlot(IcSizeType slot) override
    {
% is_jit_ic = insn.properties.include?("jit_ic_slot")
% is_ic = (!is_jit_ic) && insn.properties.include?("ic_slot")
% is_8_bit_ic = insn.properties.include?("eight_bit_ic")
% is_16_bit_ic = (!is_8_bit_ic) && insn.properties.include?("sixteen_bit_ic")
% is_8_16_bit_ic = (!is_16_bit_ic) && insn.properties.include?("eight_sixteen_bit_ic")
% if (!is_jit_ic && !is_ic)
        return 0;
% else
%   ret = insn.properties.include?("one_slot") ? 1 : 2;
        constexpr static ICSlot invalid = 0xFF;
%   if (is_16_bit_ic || is_8_16_bit_ic)
        if (slot <= 0xFF) {
            if ((slot + <%= ret %>) > 0xFF) {
                <%= op_map['imm'][0] %> = 0x100;
                return <%= ret %> + (0x100 - slot);
            }

            <%= op_map['imm'][0] %> = slot;
            return <%= ret %>;
        }

        if (slot > 0xFF && slot <= 0xFFFF) {
            <%= op_map['imm'][0] %> = slot;
            return <%= ret %>;
        }

        <%= op_map['imm'][0] %> = invalid;
        return 0;
%   end
%   if (is_8_bit_ic)
        if (slot <= 0xFF) {
            if ((slot + <%= ret %>) > 0xFF) {
                <%= op_map['imm'][0] %> = invalid;
                return 0x100 - slot;
            }

            <%= op_map['imm'][0] %> = slot;
            return <%= ret %>;
        }

        <%= op_map['imm'][0] %> = invalid;
        return 0;
%   end
% end
    }

    bool InlineCacheEnabled() override
    {
% is_jit_ic = insn.properties.include?("jit_ic_slot")
% is_ic = (!is_jit_ic) && insn.properties.include?("ic_slot")
% if (!is_jit_ic && !is_ic)
        return false;
% else
        return true;
% end
    }

    ICSlot GetIcSlot() override
    {
% is_jit_ic = insn.properties.include?("jit_ic_slot")
% is_ic = (!is_jit_ic) && insn.properties.include?("ic_slot")
% if (!is_jit_ic && !is_ic)
        return 0;
% else
        return <%= op_map['imm'][0] %>;
% end
    }

    bool oneByteSlotOnly() override
    {
% is_jit_ic = insn.properties.include?("jit_ic_slot")
% is_ic = (!is_jit_ic) && insn.properties.include?("ic_slot")
% if (!is_jit_ic && !is_ic)
        return false;
% end
% is_8_bit_ic = insn.properties.include?("eight_bit_ic")
% if (is_8_bit_ic)
        return true;
% else
        return false;
% end
    }

    uint8_t IcSlots() override
    {
% is_jit_ic = insn.properties.include?("jit_ic_slot")
% is_ic = (!is_jit_ic) && insn.properties.include?("ic_slot")
% if (!is_jit_ic && !is_ic)
        return 0;
% else
%   ret = insn.properties.include?("one_slot") ? 1 : 2;
        return <%= ret %>;
% end
    }

% if is_range_op
    bool IsRangeInst() const override
    {
        return true;
    }

    int64_t RangeRegsCount() override
    {
%   if insn.mnemonic == "createobjectwithexcludedkeys" or insn.mnemonic.start_with? "wide."
%       if insn.mnemonic == "wide.callthisrange" or insn.mnemonic == "createobjectwithexcludedkeys" or
%           insn.mnemonic == "wide.createobjectwithexcludedkeys"
        return <%= op_map['imm'][0] %> + 1;
%       else
        return <%= op_map['imm'][0] %>;
%       end
%   else
%       if insn.mnemonic == "callthisrange"
        return <%= op_map['imm'][1] %> + 1;
%       else
        return <%= op_map['imm'][1] %>;
%       end
%   end
    }
% end

% if ops_list.length != 0
private:
    <%= members %>
% end
};

% end
}  // namespace panda::es2panda::compiler

#endif
